package com.dolphin.permission;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.IdUtil;
import com.dolphin.commons.Constants;
import com.dolphin.model.Permission;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Controller;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author dolphin
 * @description 菜单管理
 * @date 2021/11/11 8:38
 */
public class MenuManager {
    private final static Logger LOGGER = LoggerFactory.getLogger(MenuManager.class);
    // 存储了系统所有的菜单组
    public final static List<AdminMenuGroup> SYSTEM_MENU_LIST = Collections.synchronizedList(new ArrayList<>());
    // 存储了每个插件的菜单组
    public final static Map<String, List<AdminMenuGroup>> PLUGIN_MENU_MAPS = Collections.synchronizedMap(new HashMap<>());
    // 存储了系统默认自带的菜单组
    public final static List<AdminMenuGroup> SYSTEM_DEFAULT_MENU_LIST = Collections.synchronizedList(new ArrayList<>());
    // 存储了所有CONTROLLER
    public final static List<Class<?>> CONTROLLER_CLASS_LIST = Collections.synchronizedList(new ArrayList<>());
    // 存储了每个插件所有CONTROLLER
    public final static Map<String, List<Permission>> PLUGIN_PERMISSION_MAPS = Collections.synchronizedMap(new HashMap<>());

    /**
     * @description 初始化系统菜单分组
     * @author dolphin
     */
    public static void initSystemMenuGroup() {

        AdminMenuGroup home = new AdminMenuGroup();
        home.setGroupId(Constants.ADMIN_MENU_GROUP_HOME);
        home.setIcon("layui-icon-console");
        home.setName("控制台");
        home.setUrl("/admin/dashboard");
        home.setSeq(1);
        home.setType(1);
        home.setId("1");
        home.setPid("-1");
        home.setRole(ListUtil.toList(Constants.ROLE_ADMIN, Constants.ROLE_CONTRIBUTE, Constants.ROLE_EDITOR, Constants.ROLE_USER));

        AdminMenuGroup auth = new AdminMenuGroup();
        auth.setGroupId(Constants.ADMIN_MENU_GROUP_AUTH);
        auth.setIcon("layui-icon-vercode");
        auth.setName("权限安全");
        auth.setSeq(2);
        auth.setType(1);
        auth.setId("7");
        auth.setPid("-1");
        auth.setRole(ListUtil.toList(Constants.ROLE_ADMIN));

        AdminMenuGroup writeArticle = new AdminMenuGroup();
        writeArticle.setGroupId(Constants.ADMIN_MENU_GROUP_WRITE_ARTICLE);
        writeArticle.setIcon("layui-icon-edit");
        writeArticle.setUrl("/admin/article/addPage");
        writeArticle.setName("写文章");
        writeArticle.setSeq(3);
        writeArticle.setType(1);
        writeArticle.setId("2");
        writeArticle.setPid("-1");
        writeArticle.setRole(ListUtil.toList(Constants.ROLE_ADMIN, Constants.ROLE_CONTRIBUTE, Constants.ROLE_EDITOR));

        AdminMenuGroup content = new AdminMenuGroup();
        content.setGroupId(Constants.ADMIN_MENU_GROUP_CONTENT);
        content.setIcon("layui-icon-read");
        content.setName("内容管理");
        content.setSeq(4);
        content.setType(1);
        content.setId("3");
        content.setPid("-1");
        content.setRole(ListUtil.toList(Constants.ROLE_ADMIN, Constants.ROLE_CONTRIBUTE, Constants.ROLE_EDITOR));

        AdminMenuGroup theme = new AdminMenuGroup();
        theme.setGroupId(Constants.ADMIN_MENU_GROUP_THEME);
        theme.setIcon("layui-icon-theme");
        theme.setName("主题管理");
        theme.setSeq(5);
        theme.setType(1);
        theme.setId("4");
        theme.setPid("-1");
        theme.setRole(ListUtil.toList(Constants.ROLE_ADMIN));

        AdminMenuGroup plugin = new AdminMenuGroup();
        plugin.setGroupId(Constants.ADMIN_MENU_GROUP_PLUGIN);
        plugin.setIcon("layui-icon-link");
        plugin.setName("插件管理");
        plugin.setSeq(6);
        plugin.setType(1);
        plugin.setId("5");
        plugin.setPid("-1");
        plugin.setRole(ListUtil.toList(Constants.ROLE_ADMIN));

        AdminMenuGroup setting = new AdminMenuGroup();
        setting.setGroupId(Constants.ADMIN_MENU_GROUP_SETTING);
        setting.setIcon("layui-icon-set");
        setting.setName("系统设置");
        setting.setSeq(7);
        setting.setType(1);
        setting.setPid("-1");
        setting.setId("6");
        setting.setRole(ListUtil.toList(Constants.ROLE_ADMIN));

        AdminMenuGroup log = new AdminMenuGroup();
        log.setGroupId(Constants.ADMIN_MENU_GROUP_LOG);
        log.setIcon("layui-icon-list");
        log.setName("日志相关");
        log.setSeq(8);
        log.setType(1);
        log.setPid("-1");
        log.setId("8");
        log.setRole(ListUtil.toList(Constants.ROLE_ADMIN));

        SYSTEM_DEFAULT_MENU_LIST.add(home);
        SYSTEM_DEFAULT_MENU_LIST.add(auth);
        SYSTEM_DEFAULT_MENU_LIST.add(writeArticle);
        SYSTEM_DEFAULT_MENU_LIST.add(content);
        SYSTEM_DEFAULT_MENU_LIST.add(theme);
        SYSTEM_DEFAULT_MENU_LIST.add(plugin);
        SYSTEM_DEFAULT_MENU_LIST.add(setting);
        SYSTEM_DEFAULT_MENU_LIST.add(log);
        SYSTEM_MENU_LIST.addAll(SYSTEM_DEFAULT_MENU_LIST);
    }

    /**
     * @description 初始化系统菜单
     * @author dolphin
     */
    public static List<AdminMenuGroup> initSystemMenu() {
        initSystemMenuGroup();
        return initAdminMenu(CONTROLLER_CLASS_LIST, SYSTEM_MENU_LIST);
    }

    /**
     * @description 初始化系统菜单
     * @author dolphin
     */
    public static List<Permission> initSystemPermission(List<Class<?>> classList) {
        if (classList.isEmpty()) {
            return Collections.EMPTY_LIST;
        }
        List<Permission> list = new ArrayList<>();
        for (Class<?> clazz : classList) {
            if (clazz.getAnnotation(Controller.class) != null || clazz.getAnnotation(RestController.class) != null) {
                for (Method method : clazz.getMethods()) {
                    ApiAuth annotation = AnnotationUtils.getAnnotation(method, ApiAuth.class);
                    if (annotation != null) {
                        Permission permission = new Permission();
                        String url = getMenuUrl(clazz, method);
                        //替换路径带有{}这种的
                        Pattern p = Pattern.compile("\\{[a-zA-Z0-9]+\\}");
                        Matcher m = p.matcher(url);
                        while (m.find()) {
                            String group = m.group();
                            url = url.replace(group, "*");
                        }
                        permission.setUrl(url);
                        permission.setName(annotation.name());
                        permission.setPermissionValue(annotation.permission());
                        permission.setPermissionType(annotation.type().name());
                        permission.setEnable(Integer.valueOf(0));
                        if (!"".equals(annotation.groupId())) {
                            permission.setPermissionType(Permission.ResType.NAV_LINK.name());
                        }
                        list.add(permission);
                    }
                }
            }
        }
        return list;
    }


    /**
     * @description 初始化系统controller 类
     * @author dolphin
     */
    public static List<Class<?>> initSystemControllerClasses() {
        if (!CONTROLLER_CLASS_LIST.isEmpty()) {
            return CONTROLLER_CLASS_LIST;
        }
        try {
            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
            String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath("com.dolphin.controller") + "/**/*.class";
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            for (Resource resource : resources) {
                if (resource.isReadable()) {
                    MetadataReader metadataReader = new CachingMetadataReaderFactory().getMetadataReader(resource);
                    Class<?> clazz = ClassUtils.getDefaultClassLoader().loadClass(metadataReader.getAnnotationMetadata().getClassName());
                    CONTROLLER_CLASS_LIST.add(clazz);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("Register Menu-> Scanner system controller error:{}", e.getMessage());
        }
        return CONTROLLER_CLASS_LIST;
    }

    /**
     * @return
     * @description 初始化系统菜单项
     * @author dolphin
     * @date 2021/11/10 14:35
     */
    public static List<AdminMenuGroup> initAdminMenu(List<Class<?>> classList, List<AdminMenuGroup> adminMenuGroups) {
        int i = 0;
        for (Class<?> clazz : classList) {
            if (clazz.getAnnotation(Controller.class) != null || clazz.getAnnotation(RestController.class) != null) {
                for (Method method : clazz.getMethods()) {
                    ApiAuth annotation = AnnotationUtils.getAnnotation(method, ApiAuth.class);
                    if (annotation != null && !"".equals(annotation.groupId())) {
                        MenuItem menuItem = new MenuItem();
                        menuItem.setGroupId(annotation.groupId());
                        menuItem.setName(annotation.name());
                        menuItem.setSeq(i++);
                        menuItem.setUrl(getMenuUrl(clazz, method));
                        menuItem.setRole(ListUtil.toList(Constants.ROLE_ADMIN));
                        menuItem.setId(IdUtil.simpleUUID());
                        menuItem.setType(1);
                        AdminMenuGroup adminMenuGroup = matchAdminGroupMenu(menuItem.getGroupId(), adminMenuGroups);
                        if (adminMenuGroup != null) {
                            adminMenuGroup.getMenuItems().add(menuItem);
                        }
                    }
                }
            }
        }
        return adminMenuGroups;
    }

    /**
     * @return com.dolphin.permission.AdminMenuGroup
     * @description 匹配菜单组
     * @author dolphin
     */
    public static AdminMenuGroup matchAdminGroupMenu(String groupId, List<AdminMenuGroup> systemAdminMenuGroups) {
        for (AdminMenuGroup adminMenuGroup : systemAdminMenuGroups) {
            if (adminMenuGroup.getGroupId().equals(groupId)) {
                return adminMenuGroup;
            }
        }
        return null;
    }

    /**
     * @description 获取菜单url
     * @author dolphin
     */
    public static String getMenuUrl(Class<?> clazz, Method method) {
        RequestMapping requestMapping = AnnotationUtils.findAnnotation(clazz, RequestMapping.class);

        String methodUrl = "";
        RequestMapping methodRequestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
        if (methodRequestMapping != null && methodRequestMapping.value().length > 0) {
            methodUrl = methodRequestMapping.value()[0];
        }

        GetMapping getMapping = AnnotationUtils.getAnnotation(method, GetMapping.class);
        if (getMapping != null && getMapping.value().length > 0) {
            methodUrl = getMapping.value()[0];
        }

        PostMapping postMapping = AnnotationUtils.getAnnotation(method, PostMapping.class);
        if (postMapping != null && postMapping.value().length > 0) {
            methodUrl = postMapping.value()[0];
        }

        DeleteMapping deleteMapping = AnnotationUtils.getAnnotation(method, DeleteMapping.class);
        if (deleteMapping != null && deleteMapping.value().length > 0) {
            methodUrl = deleteMapping.value()[0];
        }

        PatchMapping patchMapping = AnnotationUtils.getAnnotation(method, PatchMapping.class);
        if (patchMapping != null && patchMapping.value().length > 0) {
            methodUrl = patchMapping.value()[0];
        }

        PutMapping putMapping = AnnotationUtils.getAnnotation(method, PutMapping.class);
        if (putMapping != null && putMapping.value().length > 0) {
            methodUrl = putMapping.value()[0];
        }

        if (StringUtils.isBlank(methodUrl)) return null;

        if (requestMapping == null || requestMapping.value().length <= 0) {
            return methodUrl;
        }
        return requestMapping.value()[0] + methodUrl;
    }

    /**
     * 根据 groupId 获取AdminMenuGroup
     *
     * @param groupId groupId
     * @return AdminMenuGroup
     */
    public static AdminMenuGroup getAdminMenuGroupByGroupId(String groupId) {
        for (AdminMenuGroup adminMenuGroup : SYSTEM_MENU_LIST) {
            if (adminMenuGroup.getGroupId().equals(groupId)) {
                return adminMenuGroup;
            }
        }
        return null;
    }

    /**
     * 是否为系统默认菜单组
     *
     * @return boolean
     */
    public static boolean isSystemDefaultAdminMenuGroup(String groupId) {
        for (AdminMenuGroup adminMenuGroup : SYSTEM_DEFAULT_MENU_LIST) {
            if (adminMenuGroup.getGroupId().equals(groupId)) {
                return true;
            }
        }
        return false;
    }
}
